
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Optional;

import cn.hutool.json.JSONConfig;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import cn.hutool.json.JSONUtil;
import com.meritdata.cloud.ai.client.entity.AsyncResult;
import com.meritdata.cloud.ai.client.entity.ClientReponse;
import com.meritdata.cloud.ai.client.util.RSAUtil;

/**
 * 异步服务访问客户端示例程序
 * 
 * @author meritdata
 * 
 */
public class ASyncHttpClient {

    // 执行中的状态
    private static String[] STATUS_ARRAY = {"SUBMITING", "SUBMITTED", "STARTING", "RUNNING"};
    // 证书key
    private static final String APP_KEY = "${token.key!''}";
    // 证书secret
    private static final String APP_SECRET = "${token.secret!''}";

    public static void main(String[] args) throws IOException {

        CloseableHttpClient client = HttpClients.createDefault();
        HttpPost httpPost = new HttpPost("${urlPrefix}/webapi/ai/model/async/execute/${service.id}");
        // 设置http的请求超时时间等配置
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectTimeout(10 * 1000)
                .setSocketTimeout(30 * 1000)
                .setConnectionRequestTimeout(10 * 1000)
                .build();
        httpPost.setConfig(requestConfig);
        // 设置执行请求的请求头
        httpPost.setHeader("App-Key", APP_KEY);
        httpPost.setHeader("App-Token", genToken(APP_SECRET));

        // 增加http post的请求参数
        // 传递流程参数，调用时可以更改参数值，也可以不传递参数，将使用默认值
        // 例如，参数名为table，值为t_movies_ratings, 则参数传递为：
        // nvps.add(new BasicNameValuePair("table", "t_movies_ratings"));
        List<NameValuePair> nvps = new ArrayList<NameValuePair>();

        <#if token ??>
        // 添加流程参数
        <#list flowParams as flowParam>
        nvps.add(new BasicNameValuePair("${flowParam.paramName}", "${flowParam.paramValue}"));
        </#list>
        </#if>

        HttpEntity executeEntity = new UrlEncodedFormEntity(nvps, "UTF-8");
        httpPost.setEntity(executeEntity);

        // 发送http请求
        HttpResponse response = client.execute(httpPost);
        int statusCode = response.getStatusLine().getStatusCode();
        if (statusCode != HttpStatus.SC_OK) {
            System.out.println("执行异常:" + statusCode);
        } else {
            // 获取请求的返回结果
            Optional<AsyncResult> result = parseEntity(response);
            Optional<String> eid = Optional.ofNullable(result.orElseGet(() -> new AsyncResult()).getEid());
            if (eid.isPresent()) {
            	System.out.println("提交任务成功：" + eid.get());
                boolean isStop = false;
                while (!isStop) {
                	System.out.println("查询任务状态");
                    // 设置状态查询请求的请求头和参数
                    HttpPost statusHttpPost = new HttpPost("${urlPrefix}/webapi/ai/model/async/status/${service.id}");
                    // 设置状态查询请求的请求头
                    statusHttpPost.setHeader("App-Key", APP_KEY);
                    statusHttpPost.setHeader("App-Token", genToken(APP_SECRET));
                    statusHttpPost.setConfig(requestConfig);
                    
                    List<NameValuePair> statusNvps = new ArrayList<NameValuePair>();
                    statusNvps.add(new BasicNameValuePair("eid", eid.get()));
                    HttpEntity statusEntity = new UrlEncodedFormEntity(statusNvps, "UTF-8");
                    statusHttpPost.setEntity(statusEntity);

                    response = client.execute(statusHttpPost);
                    statusCode = response.getStatusLine().getStatusCode();
                    result = parseEntity(response);
                    Optional<String> status = Optional.ofNullable(result.orElseGet(() -> new AsyncResult()).getStatus());
                    if (statusCode == HttpStatus.SC_OK && status.isPresent()) {
                        System.out.println(status.get());
                        // 判断返回的提交任务的状态，如果执行完毕，则退出检测
                        long exist = Arrays.stream(STATUS_ARRAY).filter(x -> x.equals(status.get())).count();
                        if (exist == 0) {
                            isStop = true;
                        }
                    } else {
                        isStop = true;
                        System.out.println(result.get());
                    }
                    try {
                        Thread.sleep(3000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("执行结束");
            }
        }
        
        client.close();
    }
    
    /**
     * 加密token
     * @param secret
     * @return
     */
    public static String genToken(String secret) {
    	return RSAUtil.encryptByPublicKey(secret + "-" + new Date().getTime(), RSAUtil.PUBLIC_KEY);
    }

    /**
     * 解析返回的消息
     *
     * @param response
     * @return
     * @throws IOException
     */
    public static Optional<AsyncResult> parseEntity(HttpResponse response) throws IOException {
        HttpEntity responseEntity = response.getEntity();
        String content = EntityUtils.toString(responseEntity, "UTF-8");
        ClientReponse<AsyncResult> clientReponse = JSONUtil.toBean(toJsonStr(content), ClientReponse.class);
        System.out.println(clientReponse);
         Optional<AsyncResult> result = Optional.ofNullable(JSONUtil.toBean(toJsonStr(clientReponse.getData()), AsyncResult.class));
        return result;
    }

      /**
      * Object转string
      * @param jsonObject
      * @return
      */
      public static String toJsonStr(Object jsonObject){
      JSONConfig config = JSONConfig.create();
      config.setIgnoreNullValue(false);
      config.setTransientSupport(false);
      return JSONUtil.toJsonStr(jsonObject,config);
      }

}